package io.alvin.jframework.plugin.security;

import io.alvin.jframework.plugin.security.realm.CustomRealm;
import io.alvin.jframework.plugin.security.realm.DefaultJdbcRealm;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.CachingSecurityManager;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.ShiroFilter;

import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 安全过滤器，框架中最核心的对象，继承ShiroFilter。
 * 拥有两个自定义的Realm：JdbcRealm（SQL配置） 和 CustomRealm（Security接口实现）
 *
 * Created by Alvin on 2017/7/15.
 */
public class SecurityFilter extends ShiroFilter {

    @Override
    public void init() throws Exception {
        super.init();
        WebSecurityManager webSecurityManager = super.getSecurityManager();
        // 设置Realm，可同时支持多个Realm，并按照先后顺序用逗号分隔
        setRealms(webSecurityManager);
        // 设置Cache，用于减少数据库查询次数，降低I/O访问
        setCache(webSecurityManager);
    }

    private void setRealms(WebSecurityManager webSecurityManager) {
        // 读取security.realm配置项
        String securityRealms = SecurityConfig.getRealms();
        if (securityRealms != null) {
            // 根据逗号进行拆分
            String[] securityRealmArray = securityRealms.split(",");
            if (securityRealmArray.length > 0) {
                // 使Realm具备唯一性与顺序性
                Set<Realm> realms = new LinkedHashSet<>();
                for (String securityRealm : securityRealmArray) {
                    if (securityRealm.equalsIgnoreCase(SecurityConstant.REALMS_JDBC)) {
                        // 添加基于JDBC的Realm，需配置相关SQL查询语句
                        addJdbcRealm(realms);
                    } else if (securityRealm.equalsIgnoreCase(SecurityConstant.REALMS_CUSTOM)) {
                        // 添加基于定制化的Realm，需要实现Security接口
                        addCustomRealm(realms);
                    }
                }
                RealmSecurityManager realmSecurityManager = (RealmSecurityManager)webSecurityManager;
                realmSecurityManager.setRealms(realms); // 设置Realm
            }
        }
    }

    private void addJdbcRealm(Set<Realm> realms) {
        // 添加自己实现的基于JDBC的Realm
        DefaultJdbcRealm jdbcRealm = new DefaultJdbcRealm();
        realms.add(jdbcRealm);
    }

    private void addCustomRealm(Set<Realm> realms) {
        // 读取security.custom.class配置项
        Security security = SecurityConfig.getSecurity();
        // 添加自己实现的Realm
        CustomRealm customRealm = new CustomRealm(security);
        realms.add(customRealm);
    }

    private void setCache(WebSecurityManager webSecurityManager) {
        // 读取 security.cacheable 配置项
        if (SecurityConfig.isCacheable()) {
            CachingSecurityManager cachingSecurityManager = (CachingSecurityManager) webSecurityManager;
            // 使用基于内存的CacheManager
            CacheManager cacheManager = new MemoryConstrainedCacheManager();
            cachingSecurityManager.setCacheManager(cacheManager);
        }
    }
}
